package api

import (
	"demo/src/app"
	"demo/src/controller"
	"demo/src/service/publish"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"
)

func init() {
	app.Application.Controller(new(FileController))
}

type FileController struct {
	app.CommonComponent
	PublishService *publish.PublishService `bean:"PublishService"`
}

func (f *FileController) ToHandlers() []controller.Handler {
	return []controller.Handler{f.upload(), f.download()}
}

func (f *FileController) upload() controller.Handler {
	return controller.PostHandler("/file/upload", func(ctx map[string]any, r *http.Request, w http.ResponseWriter) {
		reader, err := r.MultipartReader()
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), 500)
			return
		}
		formMap := make(map[string]string)
		multiFile := make(map[string]*os.File)
		for {
			part, err := reader.NextPart()
			if err != nil {
				break
			}
			switch part.FormName() {
			case "path":
				textBuf := make([]byte, 4*128)
				read, err := part.Read(textBuf)
				if err != nil {
					if err != io.EOF {
						log.Println(err)
						http.Error(w, err.Error(), 500)
						return
					}
				}
				formMap[part.FormName()] = string(textBuf[:read])
			case "project":
				textBuf := make([]byte, 4*128)
				read, err := part.Read(textBuf)
				if err != nil {
					if err != io.EOF {
						log.Println(err)
						http.Error(w, err.Error(), 500)
						return
					}
				}
				formMap[part.FormName()] = string(textBuf[:read])
			case "file":
				temp, err := os.CreateTemp("./", fmt.Sprintf("temp.*.%s.data", part.FileName()))
				if err != nil {
					log.Println(err)
					http.Error(w, err.Error(), 500)
					return
				}
				written, err := io.Copy(temp, part)
				if err != nil {
					log.Println(err)
					http.Error(w, err.Error(), 500)
					return
				}
				log.Printf("写出 %d 字节到暂存文件", written)
				multiFile[part.FormName()] = temp
			}
		}
		log.Println(formMap)
		root := ctx["File"].(map[string]any)["Root"].(string)
		f.PublishService.UploadProject(publish.Project{
			Path:    filepath.Join(root, formMap["path"]),
			Project: formMap["project"],
			File:    multiFile["file"],
		})
	})
}

func (f *FileController) download() controller.Handler {
	return controller.GetHandler("/file/:filePath", func(ctx map[string]any, r *http.Request, w http.ResponseWriter) {
		fileName := ctx["filePath"]
		log.Println(fileName)
		root, ok := ctx["File"].(map[string]any)["Root"]
		log.Println(root)
		log.Println(ok)
		if fileName == "" {
			w.WriteHeader(404)
			w.Write([]byte(http.StatusText(404)))
			return
		}
		if ok {
			file := filepath.Join(root.(string), fileName.(string))
			log.Println("getFile: " + file)
			http.ServeFile(w, r, file)
		} else {
			file := filepath.Join("./", fileName.(string))
			log.Println("getFile: " + file)
			http.ServeFile(w, r, file)
		}
	})
}
